// VisioUtility.cs
// compile with: /doc:VisioUtility.xml
// <copyright>Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <summary>This file contains utility classes and methods that perform
// operations commonly performed on Visio objects.</summary>

using System;
using System.Diagnostics;
using System.Resources;
using System.Windows.Forms;

using Visio = Microsoft.Office.Interop.Visio;

using System.Runtime.InteropServices;

namespace Scenario.Modeler
{

	/// <summary>The Utility class contains various utility methods.</summary>
	public class Utility {

		/// <summary>This method draws a rectangle and sets the appropriate
		/// properties of the shape to make it a text-only shape.</summary>
		/// <param name="targetPage">Reference to the page that will be used
		/// </param>
		/// <param name="shapeText">Text to be set in the text-only shape
		/// </param>
		/// <returns>Text-only shape that is created, otherwise null</returns>
		public static Visio.Shape CreateTextOnlyShape(Visio.Page targetPage,string sNameU, string shapeText, double x, double y, double deltax, double deltay) 
		{
			const string styleName = "Normal";

			Microsoft.Office.Interop.Visio.Shape textOnlyShape = null;

			try 
			{
				// Draw a rectangle shape.
				textOnlyShape = targetPage.DrawRectangle(x, y, x+deltax, y-deltay);

				textOnlyShape.Name = sNameU;
				// Set the LineStyle and FillStyle properties of the shape.  The
				// Text Only style is one of the Visio default document styles.
				textOnlyShape.LineStyle = styleName;
				textOnlyShape.FillStyle = styleName;

				// Set the shape text with the text passed in.
				textOnlyShape.Text = shapeText;
			}
			catch (Exception err) 
			{
				System.Diagnostics.Debug.WriteLine(err.Message);
			}

			return textOnlyShape;
		}



		public static Visio.Shape CreateTextOnlyShape(Visio.Page targetPage,string sNameU, string shapeText) 
		{
			return Utility.CreateTextOnlyShape (targetPage, sNameU, shapeText,2, 9, 4.5, 1);
		}


		[CLSCompliant(false)]
		public static System.Drawing.Point MapVisioToWindows(
			AxMicrosoft.Office.Interop.VisOcx.AxDrawingControl drawingControl,
			double visioX,
			double visioY) {

			// The drawing control object must be valid.
			if (drawingControl == null) {

				// Throw a meaningful error.
				throw new ArgumentNullException("drawingControl");
			}

			int windowsX = 0;
			int windowsY = 0;
			double visioLeft;
			double visioTop;
			double visioWidth;
			double visioHeight;
			int pixelLeft;
			int pixelTop;
			int pixelWidth;
			int pixelHeight;
			Visio.Window referenceWindow;

			referenceWindow = (Visio.Window)drawingControl.Window;

			// Get the window coordinates in Visio units.
			referenceWindow.GetViewRect(out visioLeft, out visioTop,
				out visioWidth, out visioHeight);

			// Get the window coordinates in pixels.
			referenceWindow.GetWindowRect(out pixelLeft, out pixelTop,
				out pixelWidth, out pixelHeight);

			// Convert the X coordinate by using pixels per inch from the
			// width values.
			windowsX = (int)(pixelLeft +
				((pixelWidth / visioWidth) * (visioX - visioLeft)));

			// Convert the Y coordinate by using pixels per inch from the
			// height values and transform from a top-left origin (windows
			// coordinates) to a bottom-left origin (Visio coordinates).
			windowsY = (int)(pixelTop +
				((pixelHeight / visioHeight) * (visioTop - visioY)));

			return new System.Drawing.Point(windowsX, windowsY);		
		}

		/// <summary>The GetClickedShape method finds a shape at the specified
		/// location within a default tolerance.</summary>
		/// <param name="drawingControl">Drawing control with the Visio page
		///  containing the location.</param>
		/// <param name="clickLocationX">The X coordinate of the location in
		/// Visio page units (inches).</param>
		/// <param name="clickLocationY">The Y coordinate of the location in
		/// Visio page units (inches).</param>
		/// <returns>The Visio shape at the location or null if no shape is
		/// found.</returns>
		[CLSCompliant(false)]
		public static Visio.Shape GetClickedShape(
			AxMicrosoft.Office.Interop.VisOcx.AxDrawingControl drawingControl,
			double clickLocationX,
			double clickLocationY) {

			const double Tolerance = .0001;

			return GetClickedShape(
				drawingControl, clickLocationX, clickLocationY, Tolerance);
		}

		/// <summary>The GetClickedShape method finds a shape at the specified
		/// location.</summary>
		/// <remarks>If there are more than one shape at the location the top
		/// shape in Z order is returned.</remarks>
		/// <param name="drawingControl">Drawing control with the Visio page
		///  containing the location.</param>
		/// <param name="clickLocationX">The X coordinate of the location in
		/// Visio page units (inches).</param>
		/// <param name="clickLocationY">The Y coordinate of the location in
		/// Visio page units (inches).</param>
		/// <param name="tolerance">The distance from the location to an
		/// included shape.</param>
		/// <returns>The Visio shape at the location or null if no shape is
		/// found.</returns>
		[CLSCompliant(false)]
		public static Visio.Shape GetClickedShape(
			AxMicrosoft.Office.Interop.VisOcx.AxDrawingControl drawingControl,
			double clickLocationX,
			double clickLocationY,
			double tolerance) {

			// The drawing control object must be valid.
			if (drawingControl == null) {

				// Throw a meaningful error.
				throw new ArgumentNullException("drawingControl");
			}

			Visio.Shape foundShape = null;

			Visio.Page currentPage;

			currentPage = drawingControl.Window.PageAsObj;

			// Use the spatial search method to return a list of
			// shapes at the location.
			Visio.Selection foundShapes = currentPage.get_SpatialSearch(
				clickLocationX, clickLocationY,
				(short)Visio.VisSpatialRelationCodes.visSpatialContainedIn,
				tolerance, 
				(short)Visio.VisSpatialRelationFlags.visSpatialFrontToBack);

			if (foundShapes.Count > 0) {

				// The selection collection of shapes is 1-based, so
				// the first shape is at index 1.
				foundShape = foundShapes[1];
			}

			return foundShape;
		}

		/// <summary>The GetShapeFromArguments method returns a reference to
		/// a shape given the command line arguments.</summary>
		/// <param name="visioApplication">The Visio application.</param>
		/// <param name="arguments">The command line arguments string containing:
		///  /doc=id /page=id /shape=sheet.id.</param>
		/// <returns>The Visio shape or null.</returns>
		[CLSCompliant(false)]
		public static Visio.Shape GetShapeFromArguments(
			Microsoft.Office.Interop.Visio.Application visioApplication,
			string arguments) {

			const char equal = '=';
			const char argumentDelimiter = '/';

			// Standard Visio add-on command line arguments.
			const string commandLineArgumentDoc = "doc";
			const string commandLineArgumentPage = "page";
			const string commandLineArgumentShape = "shape";

			int index;
			int docId = -1;
			int pageId = -1;
			string shapeId = "";
			string[] contextParts;
			string contextPart;
			string[] argumentParts;
			Visio.Document document = null;
			Visio.Page page = null;
			Visio.Shape targetShape = null;

			// Parse the command line arguments.
			contextParts = arguments.Trim().Split(argumentDelimiter);

			for (index = contextParts.GetLowerBound(0); index <= 
				contextParts.GetUpperBound(0); index++) {

				contextPart = contextParts[index].Trim();

				if (contextPart.Length > 0) {

					// Separate the parameter from the parameter value.
					argumentParts = contextPart.Split(equal);

					if (argumentParts.GetUpperBound(0) == 1) {

						// Get the doc, page, and shape argument values.
						if (commandLineArgumentDoc.Equals(argumentParts[0])) {

							docId = Convert.ToInt16(argumentParts[1],
								System.Globalization.CultureInfo.InvariantCulture);
						}
						else if (commandLineArgumentPage.Equals(argumentParts[0])) {

							pageId = Convert.ToInt16(argumentParts[1],
								System.Globalization.CultureInfo.InvariantCulture);
						}
						else  if (commandLineArgumentShape.Equals(argumentParts[0])) {

							shapeId = argumentParts[1];
						}
					}
				}
			}

			// If the command line arguments contains document, page, and shape
			// then look up the shape.
			if ((docId > 0) && (pageId > 0) && (shapeId.Length > 0)) {

				document = visioApplication.Documents[docId];
				page = document.Pages[pageId];
				targetShape = page.Shapes[shapeId];
			}

			return targetShape;
		}

		/// <summary>The OpenStencil method opens the specified Visio document
		///  stencil.</summary>
		/// <param name="drawingControl">Drawing control with the collection of
		///  Visio documents to add the new stencil to.</param>
		/// <param name="stencilPath">The stencil path\filename to open.</param>
		/// <returns>Document object if the stencil is opened successfully.
		/// A COMException is thrown if the stencil cannot be opened.</returns>
		[CLSCompliant(false)]
		public static Visio.Document OpenStencil(
			AxMicrosoft.Office.Interop.VisOcx.AxDrawingControl drawingControl,
			string stencilPath) {

			// The drawing control object must be valid.
			if (drawingControl == null) {

				// Throw a meaningful error.
				throw new ArgumentNullException("drawingControl");
			}

			Visio.Document targetStencil = null;

			Visio.Documents targetDocuments;
			targetDocuments = (Visio.Documents)drawingControl.Window.Application.Documents;


			targetStencil = targetDocuments.OpenEx(stencilPath,	
				(short)Visio.VisOpenSaveArgs.visOpenRO |
				(short)Visio.VisOpenSaveArgs.visOpenHidden |
				(short)Visio.VisOpenSaveArgs.visOpenMinimized |
				(short)Visio.VisOpenSaveArgs.visOpenNoWorkspace);

			return(targetStencil);
		}

		/// <summary>The GetMaster method gets the master by name.</summary>
		/// <param name="drawingControl">Drawing control with the collection of
		///  Visio documents that contain the stencil and masters.</param>
		/// <param name="stencilPath">The stencil path\filename.</param>
		/// <param name="masterNameU">The universal name of the master.</param>
		/// <returns>Master object if found. A COMException is thrown if not found.</returns>
		[CLSCompliant(false)]
		public static Visio.Master GetMaster(
			AxMicrosoft.Office.Interop.VisOcx.AxDrawingControl drawingControl,
			string stencilPath,
			string masterNameU) {

			// The drawing control object must be valid.
			if (drawingControl == null) {

				// Throw a meaningful error.
				throw new ArgumentNullException("drawingControl");
			}

			Visio.Master targetMaster = null;

			Visio.Document targetDocument;
			Visio.Masters targetMasters;

			targetDocument = OpenStencil(drawingControl, stencilPath);
			targetMasters = targetDocument.Masters;
			targetMaster = targetMasters.get_ItemU(masterNameU);

			return(targetMaster);
		}

		static public string GetMasterNameU(Visio.Shape shape)
		{
			string sNameU = string.Empty;

			if ( shape == null) 
			{
				return sNameU;
			}

			if ( shape.Master == null) 
			{
				return Utility.GetMasterNameUBase(shape.NameU);
			}
			else
			{	
				return Utility.GetMasterNameUBase(shape.Master.NameU);
			}
		}

		static public string GetMasterNameUBase(string sNameU)
		{
			String sShapeId = sNameU;
			int pos = sShapeId.IndexOf(".");

			if ( pos > 0 )
			{
				sShapeId=sShapeId.Substring (0,pos);
			}

			return sShapeId;
		}

		static public void setUpVisioDrawing(AxMicrosoft.Office.Interop.VisOcx.AxDrawingControl drawingControl) 
		{
			try 
			{
				for (int i = drawingControl.Window.Windows.Count; i > 0; i--) 
				{
					Visio.Window visWindow;
					int windowType;

					visWindow = drawingControl.Window.Windows.get_ItemEx(i);
					windowType = visWindow.Type;

					switch (visWindow.ID) 
					{
						//case (int) Visio.VisWinTypes.visAnchorBarAddon:
						//case (int) Visio.VisWinTypes.visAnchorBarBuiltIn:
						//case (int) Visio.VisWinTypes.visApplication:
						//case (int) Visio.VisWinTypes.visDockedStencilAddon:
						//case (int) Visio.VisWinTypes.visDockedStencilBuiltIn:
						//case (int) Visio.VisWinTypes.visDrawing:
						//case (int) Visio.VisWinTypes.visDrawingAddon:
						//case (int) Visio.VisWinTypes.visIcon:
						//case (int) Visio.VisWinTypes.visInvalWinID:
						//case (int) Visio.VisWinTypes.visMasterGroupWin:
						//case (int) Visio.VisWinTypes.visMasterWin:
						//case (int) Visio.VisWinTypes.visPageGroupWin:
						//case (int) Visio.VisWinTypes.visPageWin:
						//case (int) Visio.VisWinTypes.visSheet:
						case (int) Visio.VisWinTypes.visStencilAddon:
						
						
						case (int) Visio.VisWinTypes.visWinIDMasterExplorer:
						case (int) Visio.VisWinTypes.visWinIDPanZoom:
						
						case (int) Visio.VisWinTypes.visWinIDStencilExplorer:
							visWindow.Visible = true;
							visWindow.WindowState =	
								(short) Visio.VisWindowStates.visWSDockedLeft | 
								(short) Visio.VisWindowStates.visWSDockedBottom;

							break;

						case (int) Visio.VisWinTypes.visWinIDShapeSearch:
						case (int) Visio.VisWinTypes.visWinIDSizePos:
						case (int) Visio.VisWinTypes.visWinIDCustProp:
						case (int) Visio.VisWinTypes.visWinIDDrawingExplorer:
							visWindow.WindowState =	
								(short) Visio.VisWindowStates.visWSDockedLeft | 
								(short) Visio.VisWindowStates.visWSDockedTop;
							visWindow.Visible = false;
							break;

						default:
							break;
					}
				}

				// Use the Visio window to set the visible user interface parts of the window.
				Visio.Window targetWindow;
				targetWindow = (Visio.Window)drawingControl.Window;

				//targetWindow.ShowRulers = 0;
				//targetWindow.ShowPageTabs = false;
				//targetWindow.ShowScrollBars = 1;
				targetWindow.ShowGrid = 1;
				//targetWindow.Zoom = 0.50;

				// Position the furniture shapes relative to the page.
				double pageLeft;
				double pageTop;
				double pageWidth;
				double pageHeight;
				targetWindow.GetViewRect(out pageLeft, out pageTop, out pageWidth, out pageHeight);


				// The drawing control is displaying a newly opened document.
				// Set the saved flag to true.
				drawingControl.Document.Saved = true;
			}

			catch (System.Runtime.InteropServices.COMException) 
			{
				throw;
			}

			return;
		}
	}
}



namespace OleCommandTarget
{
	[StructLayout(LayoutKind.Sequential)]
	public struct OLECMDTEXT
	{
		public UInt32 cmdtextf;
		public UInt32 cwActual;
		public UInt32 cwBuf;
		public char rgwz;
	}

	[StructLayout(LayoutKind.Sequential)]
	public struct OLECMD
	{
		public UInt32 cmdID;
		public UInt64 cmdf;
	}

	[ComImport(), Guid("B722BCCB-4E68-101B-A2BC-00AA00404770"),
	InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
	public interface IOleCommandTarget
	{
		[PreserveSig()]
		int QueryStatus( [In, MarshalAs(UnmanagedType.Struct)] ref Guid 
			pguidCmdGroup, [MarshalAs(UnmanagedType.U4)] int cCmds, 
			[In, Out] IntPtr prgCmds, [In, Out] IntPtr pCmdText);

		[PreserveSig()]
		int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdExecOpt, 
			object[] pvaIn, [In, Out, MarshalAs(UnmanagedType.LPArray)] 
			object[] pvaOut);
	}
}
